
/*
  DustSensor
  Measures the Sensordata from a STBM 271 Dust Sensor Module
  Hannes Hassler 2012
  GNU GENERAL PUBLIC LICENSE (GPL3)
  http://www.gnu.org/licenses/gpl-3.0.html 
 */
 
#include "Wire.h"
#include <DS1107H.h>
 
#define PIN_V_OUT1  3
#define PIN_V_OUT2  2

#define COUNTER_LIMIT 100000

#define SEGLengthArrLength 20

#define TEMPERATURE_PIN 3

#define SWITCH_PIN 4

int tempVal;
float tempAverage;
float calcResist;
float calcTemp;

char ch;

long numberOfSamples=500000;
int measurementRounds=1;

long counter=COUNTER_LIMIT;

float sumAverage=1;
float average=0;
int sampleN=10;
int temperatueSample=50;

int segLengthArrLength=SEGLengthArrLength;
long segLength[SEGLengthArrLength];
int segLenIdx=0;

boolean switchOn;
boolean scheduleOn;

int onPercentage=75;
double zielTemperatur=20;
double zielPerc;
long mIter=0;

DS1107H clock;

void setup() { 
  pinMode(PIN_V_OUT1, INPUT);     
  pinMode(PIN_V_OUT2, INPUT);
  pinMode(SWITCH_PIN, OUTPUT);  
  putSwitch(false);
  
  Serial.begin(9600);
  
  //to set the timer chip  
  /*
  byte second=0;
  byte minute=45;
  byte hour=23;
  byte dayOfWeek=1;
  byte dayOfMonth=29;
  byte month=4;
  byte year=13;
  clock.setDate(second,minute,hour,dayOfWeek,dayOfMonth,month,year);    
  */
  
  
  
}

void loop() {
  static int v = 0; 

 if (Serial.available()) { 
      ch = Serial.read();  
      switch(ch) {
       case '0'...'9':
          v = v * 10 + ch - '0';
          break;
        case 'e':
          showln("test val:",v);                      
          v = 0; break; 
        case 'a':         
         showln("measure Rounds:",measurementRounds); 
         showln("number of Samples:",numberOfSamples);  
         break;        
        case 'm':
          showln("measure Rounds:",measurementRounds); 
        case 'M':
          measurementRounds=v;
          showln("new measure Rounds:",measurementRounds); 
          v=0;
          break;
        case 'n':
          showln("number of Samples:",numberOfSamples);                                
          break;
        case 'N':
          numberOfSamples=v;
          showln("new number of Samples:",numberOfSamples); 
          v=0;
          break;
       case 'p':
          onPercentage=v;
          showln("new onPercentage:",onPercentage); 
          v=0;
          break;
       case 's':
           zielTemperatur=v;
           zielPerc=stablePs(zielTemperatur);
           showln("P_s=",zielPerc);
           v=0;
           break;       
       case 't':
          putSwitch(!switchOn);
          showln("put Switch on=",switchOn);
          break;
      case 'z':
          zielTemperatur=v;
          showln("Zieltemperatur=",zielTemperatur);
          v=0;
          break;
    }
  }  
  
  
  putSwitch(isOn(onPercentage)&&scheduleOn);
  tempVal=analogRead(TEMPERATURE_PIN);
  tempAverage=((tempAverage*temperatueSample)+tempVal)/(temperatueSample+1);
  
  if (counter>COUNTER_LIMIT) {     
    
     /*average=smartMeasure(PIN_V_OUT2, numberOfSamples);  
     sumAverage=((sumAverage*sampleN)+average)/(sampleN+1);
     show("smartPerc=",sumAverage);*/     
     
     //show(" potAverage=",tempAverage);
     calcResist=calcR(tempAverage);
     //show(" calcR=",calcResist);
     calcTemp=calcR2Temperatur(calcResist);
     
     boolean initialiSierung;
     if (calcTemp<=zielTemperatur-2.8)    {onPercentage=100;initialiSierung=true;}
     if (initialiSierung && calcTemp>zielTemperatur-2.8)   {onPercentage=stablePs(zielTemperatur);}
     if (calcTemp>zielTemperatur-0.7) {initialiSierung=false; onPercentage=stablePs(zielTemperatur);}
     if (!initialiSierung && calcTemp<zielTemperatur-1) {onPercentage=stablePs(zielTemperatur)+5;}
     if (calcTemp>zielTemperatur-0.2)   {onPercentage=0;}
     
     scheduleOn=isInSchedule();
     
     //45.65C
     //onPercentage=10;
     
     //59.12<Temp<=59.99
     //onPercentage=20;
     
     //71.5<Temp<72.5
     //onPercentage=30;
     
     //82.2<Temp<82.3
     //onPercentage=40;
     
     show(" mIter=",mIter++);
     show(" actTemp=",calcTemp);
     show(" Zieltemp=",zielTemperatur);
     show(" onPerc=",onPercentage);
     show(" scheduleON=",scheduleOn);
     
     clock.getDate();
     showTime(clock);
     
    counter=0;
  }  
  counter++;
             
}


float stablePs(float targetTemp) {
  
  float retVal;
  if (targetTemp<45.65)                        {retVal=P_s(targetTemp,  0.0 ,10.0, 23.00,  45.65);}
  if (45.65<=targetTemp  && targetTemp<=59.65) {retVal=P_s(targetTemp, 10.0 ,20.0, 45.65,  59.65);}
  if (59.65<=targetTemp  && targetTemp<=72.00) {retVal=P_s(targetTemp, 20.0 ,30.0, 59.65,  72.00);}
  if (72.00<=targetTemp  && targetTemp<=82.25) {retVal=P_s(targetTemp, 30.0 ,40.0, 72.00,  82.25);}  
  if (82.25<targetTemp                      )  {retVal=P_s(targetTemp, 40.0 ,50.0, 82.25,  90.00);} 
  
  return retVal;
}

float t_k(float a, float b, float T1, float T2) {
  return (b-a)/(T2-T1);
}

float t_d(float a, float b, float T1, float T2) {
  return (a*T2-b*T1)/(T2-T1);
}

float P_s(float T_s, float a, float b, float T1, float T2) {
  return t_k(a, b, T1, T2)*T_s+t_d(a, b, T1, T2);
}

boolean isInSchedule() {
  boolean retVal=false;
  clock.getDate();
  if (clock.hour>=6 && clock.hour<9) {retVal=true;}
  //if (clock.hour>=23) {retVal=true;}
  retVal=true;
  return retVal;
}


boolean isOn(long onPercentage) {
  unsigned long time = millis();
  
  //long partOfMinute= (time/1000)%(60);
  //return ((5*partOfMinute/3)<=onPercentage);
  
  long partOf10Sec= (time%10000)/100;  
  return (partOf10Sec<onPercentage);
  
}

void setEinschaltVerhaeltnis(int prozentsatz) {
  onPercentage=prozentsatz;
}


void putSwitch(boolean valueOn) {
     switchOn=valueOn;     
   if (switchOn) {
     digitalWrite(SWITCH_PIN, HIGH);
   } else {
     digitalWrite(SWITCH_PIN, LOW);
   }
}

void showln(char nameStr[], double val) {
  Serial.print(nameStr);    
  Serial.println(val);
  
}

void show(char nameStr[], double val) {
  Serial.print(nameStr);
  Serial.print(val);
}


void showSegLength() {
  int margIdx=50;
  int tabIdx=0;
  if (segLenIdx<1) {
    Serial.println("seqLenIdx=0");
  } else {
    for (int lsegIdx=0;lsegIdx<segLenIdx;lsegIdx++) {      
        Serial.print(";");
        if (tabIdx<margIdx) {           
          Serial.print(segLength[lsegIdx]);   
          tabIdx++;
        } else {        
          Serial.println(segLength[lsegIdx]);           
          tabIdx=0;
        }     
    }
    Serial.println(" "); 
  }  
}

void showTime(DS1107H timerChip) {
  Serial.print("   UT ");
  Serial.print(timerChip.hour, DEC);
  Serial.print(":");
  Serial.print(timerChip.minute, DEC);
  Serial.print(":");
  Serial.print(timerChip.second, DEC);
  Serial.print("  ");
  Serial.print(timerChip.month, DEC);
  Serial.print("/");
  Serial.print(timerChip.dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(timerChip.year, DEC);
  Serial.print("  Day_of_week:");
  Serial.println(timerChip.dayOfWeek, DEC);  
}

void resetSegLength() {  
  for (int lsegIdx=0;lsegIdx<segLengthArrLength;lsegIdx++) {
      segLength[lsegIdx]=0;
  }
  segLenIdx=0;  
}

float calcR2Temperatur(float Rt) {  
  float temperatur_it=0;  
  for (int i=0;i<5;i++) {
      temperatur_it=calcR2TempIteration(temperatur_it,Rt);
  }
  return temperatur_it;
}


float potentialCorrection (float rawPotential) {
  float correction=0;
  /*
  One can use this "table" to finetune the corrective Terms.
  Later you can derive from this empirically found data a simple linear Korrelation
  and put it into a single formula
  if (570.0<=rawPotential                      ) {correction=-3.9;}
  if (565.0<=rawPotential && rawPotential<570.0) {correction=-4.2;}
  if (560.0<=rawPotential && rawPotential<565.0) {correction=-4.5;}
  if (555.0<=rawPotential && rawPotential<560.0) {correction=-4.75;}
  if (550.0<=rawPotential && rawPotential<555.0) {correction=-5.2;}
  if (545.0<=rawPotential && rawPotential<550.0) {correction=-5.5;}
  if (540.0<=rawPotential && rawPotential<545.0) {correction=-5.7;}
  if (535.0<=rawPotential && rawPotential<540.0) {correction=-5.9;}
  if (530.0<=rawPotential && rawPotential<535.0) {correction=-6.2;}
  if (527.0<=rawPotential && rawPotential<530.0) {correction=-6.5;}
  if (525.0<=rawPotential && rawPotential<527.0) {correction=-6.7;}
  if (520.0<=rawPotential && rawPotential<525.0) {correction=-6.9;}
  if (510.0<=rawPotential && rawPotential<520.0) {correction=-7.0;}
  if (                       rawPotential<510.0) {correction=-7.1;}
  */
    
  //Linear formula, derived from above empirical Data  
  correction=(rawPotential*0.06)-38.28;
  
  return correction;
}
float calcR(float potential) {  
  
  float potentialCorr=potential+potentialCorrection(potential);
  float fixWiderstand=107.75;
  float messBereich=1023;
  return (fixWiderstand*potentialCorr)/(messBereich-potentialCorr);
}

float calcR2TempIteration(float temperatur_it, float Rt) {
      
     float R0=100.0;
     float tempertur_itSquare=temperatur_it*temperatur_it;
     float A=0.0039083;
     float B=-5.775E-007;
     float C=0;
     float temperatur_itNew=
            temperatur_it-
     (-Rt +R0*(1+A*temperatur_it+B*tempertur_itSquare))/(R0*(A+2*temperatur_it*B));
     return temperatur_itNew;
}

float mediumMeasure(int pin, int times, long numberOfSamples) {
     float sum=0;
     int dontCount=0;
     float average=0.0;
     for (int i=0;i<times;i++) {
       resetSegLength();
       float measureVal=measure(pin, numberOfSamples);
       if (measureVal>0.0) {
         sum=sum+measureVal;
       } else {
         dontCount++;
         showSegLength();
       }
     }
     if (times-dontCount>0) {
         average=sum/(times-dontCount);
     } 
     return average;
}

float measure(int pin, long numOfSamples) {
  
  int pinVal=0;
  long highCount=0;
  long lowCount=0;
  boolean prevValWasHigh=true;
  long highSegmentLength=0;
  long lowSegmentLength=0;
  for (long i=0;i<numOfSamples;i++) {    
      pinVal = digitalRead(pin);
      if (pinVal==HIGH) {
         highCount++;
         
         if (prevValWasHigh) {
            highSegmentLength++;
         } else {
            highSegmentLength=1;       
            if (segLenIdx<segLengthArrLength-1) { 
              segLength[segLenIdx]=0;
              segLength[segLenIdx+1]=lowSegmentLength;
              lowSegmentLength=0;
              segLenIdx=segLenIdx+2;
            }
         }
         
         prevValWasHigh=true;
      } else {
        lowCount++;
        
        if (prevValWasHigh) {
            lowSegmentLength=1;       
            if (segLenIdx<segLengthArrLength-1) { 
              segLength[segLenIdx]=1;
              segLength[segLenIdx+1]=highSegmentLength;
              highSegmentLength=0;
              segLenIdx=segLenIdx+2;
            }          
            
         } else {
            lowSegmentLength++;
         }
        
        
        prevValWasHigh=false;
      }        
  }  
  long sum=highCount+lowCount;
  long percentageby100=(lowCount*10000)/sum;
  float percentageby100f=percentageby100;
  float percentage=percentageby100f/100.0;
  return percentage;
}


float smartMeasure(int pin, long numOfSamples) {
  
  int prevPinVal=HIGH;
  int pinVal=HIGH;
  long highCount=0;
  long lowCount=0;
  
  long highSegmentLength=0;
  long lowSegmentLength=0;  
  
  int segLengthIdx=0;
  
  for (long i=0;i<numOfSamples;i++) {   
    
      prevPinVal=pinVal;
      pinVal = digitalRead(pin);      
      
      if (prevPinVal==HIGH && pinVal==LOW) {   
       highCount=highCount+highSegmentLength;
       lowCount=lowCount+lowSegmentLength; 
       lowSegmentLength=1;
       highSegmentLength=0;         
      }
      
      if (segLengthIdx>=segLengthArrLength-1) {          
          segLengthIdx=0;
      }
      
      if (prevPinVal==LOW && pinVal==LOW) {
         lowSegmentLength++;
      }
      
      if (lowSegmentLength>0 && prevPinVal==LOW && pinVal==HIGH) {         
         highSegmentLength=1;        
      } 

      if (highSegmentLength>0 && prevPinVal==HIGH && pinVal==HIGH) {
         highSegmentLength++;
      }    
      
      
  }  
  
  long sum=highCount+lowCount;
  long percentageby100=(lowCount*10000)/sum;
  float percentageby100f=percentageby100; 
  float percentage=percentageby100f/100.0;
  return percentage;
}


